package com.ruget.ools.log.starter.util;

import com.ruge.tool.json.JsonTool;
import com.ruge.tool.str.StringTool;
import com.ruget.ools.log.starter.annotation.SysLog;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.io.InputStreamSource;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * description 日志工具类
 * create Time at 2022/9/1 9:37
 *
 * @author alice.ruge
 * @since 0.0.7
 */
@Slf4j
public class LogUtil {

    /***
     * 获取操作信息
     * @param point {@link JoinPoint}
     * @return 获取描述信息
     */
    public static String getControllerMethodDescription(JoinPoint point) {
        try {
            // 获取连接点目标类名
            String targetName = point.getTarget().getClass().getName();
            // 获取连接点签名的方法名
            String methodName = point.getSignature().getName();
            //获取连接点参数
            Object[] args = point.getArgs();
            //根据连接点类的名字获取指定类
            Class targetClass = Class.forName(targetName);
            //获取类里面的方法
            Method[] methods = targetClass.getMethods();
            String description = "";
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    Class[] clazzs = method.getParameterTypes();
                    if (clazzs.length == args.length) {
                        description = method.getAnnotation(ApiOperation.class).value();
                        if (StringTool.isBlank(description)) {
                            description = method.getAnnotation(SysLog.class).value();
                        }
                        break;
                    }
                }
            }
            return description;
        } catch (Exception e) {
            return "";
        }
    }


    /**
     * 获取堆栈信息
     *
     * @param throwable
     * @return
     */
    public static String getStackTrace(Throwable throwable) {
        StringWriter sw = new StringWriter();
        try (PrintWriter pw = new PrintWriter(sw)) {
            throwable.printStackTrace(pw);
            return sw.toString();
        }
    }

    /**
     * 获取请求头
     *
     * @param request {@link HttpServletRequest}
     * @return 请求头
     */
    public static Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> headerMap = new HashMap<>(8);
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String name = enumeration.nextElement();
            String value = request.getHeader(name);
            headerMap.put(name, value);
        }
        return headerMap;
    }

    /**
     * 获取post参数
     *
     * @param request {@link HttpServletRequest}
     * @return 参数
     */
    public static String getPostData(HttpServletRequest request) {
        StringBuffer data = new StringBuffer();
        String line = null;
        BufferedReader reader = null;
        try {
            reader = request.getReader();
            while (null != (line = reader.readLine())) {
                data.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
            log.error("getPostData is error :{}", e.getMessage());
        }
        return data.toString();
    }

    public static List<Object> addRequestParams(JoinPoint point) {
        List<Object> logValues = new ArrayList<>();
        Object[] args = point.getArgs();
        MethodSignature ms = (MethodSignature) point.getSignature();
        Method method = ms.getMethod();
        Map<String, Object> paramsMap = new HashMap<>(16);
        for (int i = 0; i < args.length; i++) {
            Object paramValue = args[i];
            Parameter parameter = method.getParameters()[i];
            String parameterName = parameter.getName();
            RequestBody requestBody = parameter.getAnnotation(RequestBody.class);
            RequestParam requestParam = parameter.getAnnotation(RequestParam.class);
            if (null != requestParam && StringTool.isNotBlank(requestParam.value())) {
                parameterName = requestParam.value();
            }
            if (requestBody != null) {
                logValues.add(JsonTool.getObjToJson(paramValue));
            } else {
                if (paramValue instanceof HttpServletRequest) {
                    paramsMap.putAll(((HttpServletRequest) paramValue).getParameterMap());
                } else if (paramValue instanceof WebRequest) {
                    paramsMap.putAll(((WebRequest) paramValue).getParameterMap());
                } else if (paramValue instanceof MultipartFile) {
                    String filename = ((MultipartFile) paramValue).getOriginalFilename();
                    paramsMap.put(parameterName, filename);
                } else if (paramValue instanceof MultipartFile[]) {
                    MultipartFile[] files = (MultipartFile[]) paramValue;
                    if (files.length > 0) {
                        List<String> filenames = Stream.of(files)
                                .map(MultipartFile::getOriginalFilename)
                                .collect(Collectors.toList());
                        paramsMap.put(parameterName, StringTool.join(filenames));
                    }
                } else {
//                    if (paramValue == null) {
//                        paramsMap.put(parameterName, null);
//                    } else if (paramValue instanceof InputStream) {
//                        paramsMap.put(parameterName, "InputStream");
//                    } else if (paramValue instanceof InputStreamSource) {
//                        paramsMap.put(parameterName, "InputStreamSource");
//                    } else if (JsonUtil.isCanSerialize(paramValue)) {
//                        paramsMap.put(parameterName, paramValue);
//                    } else {
//                        paramsMap.put(parameterName, "此参数不支持序列化为json");
//                    }

                    if (paramValue == null) {
                        paramsMap.put(parameterName, null);
                    } else if (paramValue instanceof InputStream) {
                        paramsMap.put(parameterName, "InputStream");
                    } else if (paramValue instanceof InputStreamSource) {
                        paramsMap.put(parameterName, "InputStreamSource");
                    } else {
                        paramsMap.put(parameterName, paramValue);
                    }
                }
            }
        }
        if (paramsMap.size() > 0) {
            logValues.add(JsonTool.getObjToJson(paramsMap));
        }
        return logValues;
    }
}
